Hey there to progress the storyline of our game further, we need to give our players the ability to
control the doors in our game.
Currently, our doors have zero functionality, so we're going to have to script the functionality for
them.
Now, in each of these door models, I've added an attribute to define the type of the door.
For example, these doors are single, meaning they only have one door to move, while our door in the
front here is defined as a double door, meaning there is two hinges that need to be rotated for the
door to open and close.
Now we're going to open and close these doors using the tween service.
But you may already know that playing tweens on the server is not optimal.
This is because every step of the tween animation, the server has to constantly send out data to the
clients to update the new property that the tween is affecting.
This causes the tween to look choppy on the client.
An alternative to this problem is having the server send the tween information to the clients, and
the clients have to play the tween on their end.
But the issue with this method is that the server will not be able to keep track of the new properties
set on these instances.
So how do we go about fixing this?
Well, what we can do is we can send tween information to all of the clients.
And then when the duration for that tween is over, we apply the goal properties of the tween on the
server.
This way tweens are smooth on the client, and the server is able to keep track of the properties for
tweened instances.
So what we're going to do is we're going to go into our server script service, and inside of here we're
going to open up a module script we have in here called Better Between.
Now this module script is going to act as our own custom tween service.
So what we're going to do in here is we're first going to reference replicated storage.
And then we're also going to create the table that's going to represent this module script.
And we're going to call it Better Tween.
And we'll make sure to return that at the end here.
And then we're going to make a reference to an event inside of replicated storage called Play Tween.
And this is the event we're going to use to send information to clients about the tweens.
They need to play on their end.
So we can call this play tween event.
And it's inside of replicated storage, dot events, dot remotes, dot play tween.
Now inside of this better tween module script, we're going to have a function in here.
And we'll call this function basically just tween.
And we're going to fill out this function basically the same way we would with a regular tween.
We get passed an instance to the tween.
We get passed tween info.
And then we also get passed a table containing the goal properties for the particular instance.
Now.
Unfortunately, we are not able to send tween info data types through a remote events.
So what we'll have to do is we'll have to unpack all the information inside of this tween info into
a table, and then pass that table containing all the properties for the tweens to the clients.
So basically what we could do is we could create a table in here and we're going to call it tween data.
And this table is going to act as an array.
So we need to fill out our tween info in order.
So the first thing that a tween info is passed is going to be the time or the duration for this tween.
The next thing we need to get passed inside of this tween info is going to be the easing style for the
tween.
The next thing we're going to get past is the easing direction for the tween as well.
Now again, remember when we get past a tween info or a developer creates a new tween info instance,
if they do not supply any values to these other properties, like let's say they only passed a time
and leave the rest blank, then these will have their own default values and we don't have to worry
about them being nil.
Now the next thing a tween info needs to be passed is a property called repeat count, and that defines
the number of times the tween repeats after tweening once.
We also need to store the tween info.
Dot reverses property a boolean that tells us whether or not the tween should reverse once the initial
tween completes and tween info dot delay time is the last property which defines the amount of time
that should elapse before the tween starts.
So now that we have this tween data based on the tween info that was passed to our tween function,
we can then refer to our play tween event, and we can fire to all the clients in our game that we need
to update a tween on this instance.
So the instance passed to this function.
We're going to pass our tween data table.
And then we're going to pass the goal table that represents the properties that need to be updated for
this tween.
Now something that's very important that we need to imitate, that the regular tween service does,
is that we need to cancel tweens in case an instance is tweened on again.
So let's say we call this function on a part and we want to change the keyframe to some position.
Right.
So we do that we call the function.
And let's say the tween lasts five seconds.
However let's say only one second later this function gets called again on the exact same part.
And we've updated the position to a different area.
Well, the issue is going to be is that if there's any discrepancies between the tween duration, one
of the properties for the tween might get applied first before the other property of the tween gets
applied.
So what we need to do is we need to cancel any current tweens that are occurring on this instance before
we apply the next tween for this instance.
So basically what we could do is we could create a table up here and we're going to call this tween
threads.
Because what we're going to do is we're going to have a function that listens for when a tween completes.
So we'll call it tween completed and it gets passed an instance.
And the goal.
So this function we need to call on this particular instance once this tween completes.
So we need to calculate the duration for this tween.
And we'll create a variable.
We'll call it total duration for the tween.
And what this has to be equal to is this has to be equal to our tween info.
Dot time.
And then we need to add along with this our tween info dot delay time.
So we make sure to account for the time and the delay time if it exists.
And then we need to multiply this value by the tween info dot repeat count.
So if this tween needs to repeat multiple times, well of course the total duration for the tween is
going to be longer.
Now something that's very important that we need to do before we actually multiply this number to this
value.
Here is let's say the repeat count is zero right.
We don't want it to repeat.
And this tween is only going to run once.
Well it doesn't matter what time we calculate it here because we're going to be multiplying it by zero
which will automatically make the total duration to zero.
So we need to also account for the time where this tween will run without repeating.
So we're going to add plus one to the value here.
So for example let's say we have a tween info that's going to last two seconds.
And we have it repeat two times right.
So we get two seconds in here.
We don't add any delay time because there is none.
And we multiply the two by the repeat count plus one.
So that would be two plus one.
Which means this tween would run a total of three times.
So three times two would be a total duration of six seconds.
And then what we could do is we could use the task dot delay function in the task library to spawn our
tween completed function and a new thread.
And the duration we need to wait is the total duration that we just calculated.
So we want to wait this amount of time before applying the changes that our tween does.
So we'll wait this.
And then after this amount of time, we're going to spawn our tween completed function in a new thread.
And the things that we need to pass to this function are going to be the instance that this tween is
affecting.
And we also need to pass the goal table containing all the properties we need to apply on this instance.
So that means inside of this table here we're going to loop through every single property and value
inside of our goal table.
And what we're going to do is we're going to set on this instance the property.
Equal to this value.
So that way we're keeping track of the new properties applied to this instance after the tween completes
on the clients end.
Now, since this task delay function returns a thread data type, we can store that thread data type
within our tween threads table.
So inside of tween threads we're going to use the instance that this tween is affecting as the key inside
of this table.
So we can just pass our instance here.
And it's going to store this thread that is currently being delayed until this duration is up.
So that way if this function somehow gets called again on the same instance before it had a chance to
execute this tween completed function, then we can go ahead and cancel the thread stopping this tween
completed function from ever running again.
So we could create an if statement up here and check if inside of our tween threads table we have a
key for this instance.
If we do, then when we need to do is we need to cancel the thread for this particular instance.
And then once we do that, we can set inside of our tween threads table on this instance to be equal
to nil.
So we're basically clearing out this key value pair.
Now we also need to clear this out within the tween threads table when our tween completes as well.
So what we could do up here is we could just basically copy this.
And remove it from our table before we apply the properties.
So basically what's going on here is we pass an instance between info for that instance and then the
goal properties.
If this instance already has a tween being acted upon it, then we need to cancel that previous tween.
And then we can create this new tween and apply it on our instance.
That way, no matter what the last call of this tween function on a certain instance is guaranteed to
be the final properties applied to the instance.
This saves us from when this function may get called multiple times on the same instance.
Now, what we need to do is we need to handle this tween that gets passed to our clients.
So inside of our starter player script, we have a tween handler module script.
Inside of here.
What we could do is we could refer to our tween service.
We can refer to replicated storage.
And then we can create the table that's going to represent this tween handler.
And we'll make sure to return it at the end of our script here.
And now the only thing we need to do inside of our tween handler is to have an initialize function.
So tween handler init.
And we need to make a variable reference to that play tween event and replicated storage dot events
dot remotes dot poi tween oops.
And it looks like I didn't finish typing this out up there.
And basically all we're going to do is we're going to listen for when our play tween event gets fired.
So on client event we can connect a custom private function.
So we can call this function on client tween event.
And we'll get passed the instance between data for this instance and the goal table.
And what we could do in here is we could create our own custom tween info.
So tween info dot new and we can get our tween data table that gets passed to this function.
And basically just use the unpack function to dump all of the data stored in here and pass it to our
tween info dot new function.
Then we can use our tween service to create a new tween.
On this instance, we will pass our tween info and pass the goal table, and then we can just play it.
And then when this event gets fired, we'll just connect it to our on client tween event.
And that's all we need to do for that.
Now we can go ahead and get started on scripting the functionality for our doors, and we're going to
get to do that in the next lecture.
So I'll see you there.